import _ from 'lodash';
import * as os from 'os';
import * as fs from 'fs-extra';
import * as uuid from 'uuid';
import * as path from 'path';

import tempDir from 'temp-dir';
import childProcess from 'child_process';

export const generateUUID = () => {
  return uuid.v4();
};

export const homeDir = path.dirname((process as any).pkg ? process.execPath : (require.main ? require.main.filename : process.argv[0]));

export const isWin = process.platform === 'win32';

// https://nodejs.org/api/process.html#process_process_kill_pid_signal
export function pidIsRunning(pid: number) {
  try {
    process.kill(pid, 0);
    return true;
  } catch (e) {
    return false;
  }
}
export function sleep(ms: number) { return new Promise(resolve => setTimeout(resolve, ms)); }

export function mergeDeep (...objects) {
  const isObject = obj => obj && typeof obj === 'object';

  return objects.reduce((prev, obj) => {
    Object.keys(obj).forEach(key => {
      const pVal = prev[key];
      const oVal = obj[key];

      if (Array.isArray(pVal) && Array.isArray(oVal)) {
        prev[key] = pVal.concat(...oVal);
      } else if (isObject(pVal) && isObject(oVal)) {
        prev[key] = mergeDeep(pVal, oVal);
      } else {
        prev[key] = oVal;
      }
    });

    return prev;
  }, {});
}

export function filterNotExistParameters(json: { [x: string]: any } = {}, propsRequired: string[] = []) {
  return propsRequired.filter(paramter => {
    return !json.hasOwnProperty(paramter);
  });
}

export function serializeError(e: Error) {
  return [e.message, e.stack].join('\n');
}

export function isTrue (value: any) : boolean { return value === 'true' || value === true; }

export function executeCommand(fullCommand: string, cwd?: string, env?: { [x: string]: string } ) {
  const [command, ...commandArgs] = fullCommand.split(' ');

  return childProcess.spawn(command, commandArgs, {
    cwd,
    env: Object.assign({}, process.env, env),
    shell: process.platform === 'win32'
  });
}

/**
 * @param extension Extension to append to the path.
 */
export function createTempFile(extension?: string) {
  return path.join(tempDir, generateUUID() + extension);
}

export function createTempDirectory() {
  const randomDirName = uuid.v4();
  const randomDir = path.join(tempDir, randomDirName);
  fs.ensureDirSync(randomDir);
  return randomDir;
}

export function generateRandomZipPath(zipName = 'code.zip') {
  const randomDir = createTempDirectory();
  const zipPath = path.join(randomDir, zipName);
  return { zipPath, randomDir };
}

/**
 * Converts a tilde path to an absolute path.
 */
// export const untildify = (str: string) => str.replace(/^~($|\/|\\)/, `${os.homedir()}$1`);

export function untildify (givenPath: string) {
  if (!givenPath) { return givenPath; }
  if (givenPath === '~') { return os.homedir(); }
  if (givenPath.slice(0, 2) !== '~/') { return givenPath; }
  const restPath = givenPath.slice(2);
  return path.join(os.homedir(), restPath.split('/').join(path.sep));
}